/**
 * @description user controller
 * @author 高
 */

const Service = require("../service/user");
const { SuccessModel, ErrorModel } = require("../model/ResModel");
const {
  registerUserNameNotExistInfo,
  registerUserNameExistInfo,
  registerFailInfo,
  loginFailInfo,
  deleteUserFailInfo,
  changeInfoFailInfo,
  changePasswordFailInfo
} = require("../model/ErrorInfo");
const doCrypto = require("../utils/cryp");
const { getUserInfo, deleteUser, updateUser } = require("../service/user");

/**
  *用户名是否存在
  * @param {String} userName 用户名
  * 这个是给前端用的，提高用户体验，但是前端有权利不使用这个接口，所以我们在真正实现注册时，还要再次验证用户是否存在
  */
async function isExist(userName) {
  // 业务逻辑处理
  // 调用service 获取数据 返回统一格式
  const userInfo = await Service.getUserInfo(userName);

  if (userInfo) {
    // 已存在
    return new SuccessModel(userInfo);
  } else {
    // 不存在
    return new ErrorModel(registerUserNameNotExistInfo);
  }
}

/**
 * 注册
 * @param {String} userName 用户名
 * @param {String} password 密码
 * @param {number} gender 性别[1 男， 2 女， 3 保密]
 */
async function register({ userName, password, gender }) {
  // 获取用户信息
  const userInfo = await Service.getUserInfo(userName);
  if (userInfo) {
    // 已存在
    return new ErrorModel(registerUserNameExistInfo);
  }

  // 注册 service
  try {
    await Service.createUser({
      userName,
      // 密码注册时直接给密码加密
      password: doCrypto(password),
      gender
    });
    // 注册成功可以什么都不用返回，直接返回成功信息即可
    return new SuccessModel();
  } catch (ex) {
    // 打印错误信息  stack错误栈
    console.error(ex.message, ex.stack);
    // 注册失败，返回注册失败信息
    return new ErrorModel(registerFailInfo);
  }
}

/**
 * 登录
 * @param {object} ctx koa2中的ctx
 * @param {string} username 用户名
 * @param {string} password 密码
 */
async function login(ctx, userName, password) {
  // 登录成功后 用户信息放到session中  ctx.session.userInfo = xxx; 用户的角色等信息
  // 登录的本质是通过用户名和密码来查询用户是否存在
  // 密码要做加密处理 doCrypto()
  const userInfo = await getUserInfo(userName, doCrypto(password));
  if (!userInfo) {
    // 登录失败返回失败的信息
    return new ErrorModel(loginFailInfo);
  }

  // 登录成功
  if (ctx.session.userInfo == null) {
    ctx.session.userInfo = userInfo;
  }

  return new SuccessModel();
}

/**
 * 删除当前用户
 * @param {string} username 用户名
 */
async function deleteCurUser(userName) {
  // 调用service中的删除
  const result = await deleteUser(userName);

  if (result) {
    // 成功
    return new SuccessModel();
  }

  // 失败
  return new ErrorModel(deleteUserFailInfo);
}

/**
 * 修改用户信息
 * @param {object} ctx
 * @param {string} nickName
 * @param {string} city
 * @param {string} picture
 */
async function changeInfo(ctx, { nickName, city, picture }) {
  const { userName } = ctx.session.userInfo;
  if (!nickName) {
    nickName = nickName;
  }
  // service 修改
  const result = await updateUser({
    newNickName: nickName,
    newCity: city,
    newPicture: picture
  }, {
    userName
  });

  if (result) {
    // 执行成功 更改session
    Object.assign(ctx.session.userInfo, {
      nickName, city, picture
    });

    // 返回
    return new SuccessModel();
  }

  // 失败
  return new ErrorModel(changeInfoFailInfo);
}

/**
 * 更改用户密码 传递的顺序比较固定
 * @param {String} userName
 * @param {String} password
 * @param {String} newPassword
 */
async function changePassword(userName, password, newPassword) {
  // 调用service
  const result = await updateUser(
    { newPassword: doCrypto(newPassword) },
    {
      userName,
      password: doCrypto(password)
    }
  );

  // 成功
  if (result) {
    return new SuccessModel();
  }

  // 失败
  return new ErrorModel(changePasswordFailInfo);
}

/**
 * 退出登录
 * @param {Object} ctx
 */
async function logout(ctx) {
  delete ctx.session.userInfo;
  return new SuccessModel();
}

module.exports = {
  isExist,
  register,
  login,
  deleteCurUser,
  changeInfo,
  changePassword,
  logout
};